package com.wlyy.starter.mybatis.expand;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.wlyy.starter.mybatis.SQLUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

@Slf4j
public class InsertOrUpdateAll extends AbstractMethod {
    public final static String METHOD_ID = "insertOrUpdateAll";
    public InsertOrUpdateAll(String name) {
        super(name);
    }
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        final String sql = "<script>insert into %s (%s) values %s as new on duplicate key update %s</script>";
        final String columnSql = SQLUtil.getAllColumn(tableInfo);
        final String valueSql = prepareValueSql(tableInfo);
        final String updateSql = prepareUpdateSql(tableInfo);
        final String sqlResult = String.format(sql, tableInfo.getTableName(), columnSql, valueSql, updateSql);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
        return this.addInsertMappedStatement(mapperClass, modelClass, "insertOrUpdateAll", sqlSource, new NoKeyGenerator(), null, null);
    }

    protected String prepareValueSql(TableInfo tableInfo) {
        final StringBuilder valueSql = new StringBuilder();
        valueSql.append("<foreach collection=\"" + COLLECTION + "\" item=\"" + ENTITY + "\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
        valueSql.append("#{" + ENTITY + ".").append(tableInfo.getKeyProperty()).append("}");
        tableInfo.getFieldList().forEach(x -> valueSql.append(",#{" + ENTITY + ".").append(x.getProperty()).append("}"));
        return valueSql.append("</foreach>").toString();
    }


    private String prepareUpdateSql(TableInfo tableInfo) {
        StringBuilder updateSql = new StringBuilder();
        tableInfo.getFieldList().forEach(f -> updateSql.append(", ").append(f.getColumn()).append(" = new.").append(f.getColumn()));
        return updateSql.substring(1);
    }
}
